package top.hekun.study.annotations.processor;


import com.google.auto.service.AutoService;
import com.sun.source.util.Trees;
import com.sun.tools.javac.processing.JavacProcessingEnvironment;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.TreeMaker;
import com.sun.tools.javac.util.Context;
import top.hekun.study.annotations.TrisceliVersion;

import javax.annotation.processing.*;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;
import javax.tools.Diagnostic;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Set;


/**
 * @Author: 贺坤
 * @Date: 2022/12/29 15:25
 */
@AutoService(Processor.class)
public class TrisceliVersionProcessor extends AbstractProcessor {
    private Types mTypeUtils;
    private Messager mMessager;
    private Filer mFiler;
    private Elements mElementUtils;
    private Trees trees;
    private TreeMaker treeMaker;

    private static <T> T jbUnwrap(Class<? extends T> iface, T wrapper) {
        T unwrapped = null;
        try {
            final Class<?> apiWrappers = wrapper.getClass().getClassLoader().loadClass("org.jetbrains.jps.javac.APIWrappers");
            final Method unwrapMethod = apiWrappers.getDeclaredMethod("unwrap", Class.class, Object.class);
            unwrapped = iface.cast(unwrapMethod.invoke(null, iface, wrapper));
        } catch (Throwable ignored) {
        }
        return unwrapped != null ? unwrapped : wrapper;
    }

    /**
     * 初始化处理器
     * 这个方法用于初始化处理器，方法中有一个ProcessingEnvironment类型的参数，ProcessingEnvironment是一个注解处理工具的集合。它包含了众多工具类。例如：
     * Filer可以用来编写新文件；
     * Messager可以用来打印错误信息；
     * Elements是一个可以处理Element的工具类
     *
     * @param processingEnvironment 提供了一系列的实用工具
     */
    @Override
    public synchronized void init(ProcessingEnvironment processingEnvironment) {
        super.init(processingEnvironment);
        this.mTypeUtils = processingEnvironment.getTypeUtils();
        this.mMessager = processingEnvironment.getMessager();
        this.mFiler = processingEnvironment.getFiler();
        this.mElementUtils = processingEnvironment.getElementUtils();
        ProcessingEnvironment unwrappedProcessingEnv = jbUnwrap(ProcessingEnvironment.class, processingEnv);
        this.trees = Trees.instance(unwrappedProcessingEnv);
        Context context = ((JavacProcessingEnvironment) processingEnv).getContext();
        this.treeMaker = TreeMaker.instance(context);
        printMessage("初始化处理器");

    }

    /**
     * ，用来指定当前正在使用的Java版本，通常return SourceVersion.latestSupported()即可。
     *
     * @return
     */
    @Override
    public SourceVersion getSupportedSourceVersion() {
        printMessage("获取支持的源版本");
        return SourceVersion.latestSupported();
    }

    /**
     * 这个方法的返回值是一个Set集合，集合中指要处理的注解类型的名称(这里必须是完整的包名+类名，例如com.example.annotation.Factory)
     */
    @Override
    public Set<String> getSupportedAnnotationTypes() {
        printMessage("获取支持的注释类型");
        HashSet<String> set = new HashSet<>();
        set.add(TrisceliVersion.class.getName()); // 支持解析的注解
        return set;
    }

    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        printMessage("过程");
        for (TypeElement t : annotations) {
            //	扫描所有被@TrisceliVersion注解的元素
            for (Element element : roundEnv.getElementsAnnotatedWith(t)) {
                // 获取到给定注解的element（element可以是一个类、方法、包等）
                printMessage(element.toString());
                Elements elementUtils = processingEnv.getElementUtils();
                JCTree.JCVariableDecl jcv = (JCTree.JCVariableDecl) trees.getTree(element);
                // 给这个字段赋值，也就是getVersion的返回值
                jcv.init = treeMaker.Literal(getVersion());

            }
        }


//        printFile();

        return false;
    }

    /**
     * 输出日志
     * 注解处理器的日志都要使用Messager发送，最终会以编译结果的形式呈现出来；
     *
     * @param msg
     */
    private void printMessage(String msg) {
        processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, msg);
    }

    //    private void printFile() throws IOException {
//        this.processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, "doing print");
//        //通过向Filer声明自己想要创建的java文件包名，就能获取其writer
//        JavaFileObject fileObject = this.processingEnv.getFiler().createSourceFile("test.mipa.testSrcFile.myClass1");
//        Writer writer = fileObject.openWriter();
//
//        //实际应用应该需要使用JavaPoet等自动代码生成功能
//        String classFileStr = "package test.mipa.estSrcFile; \n" +
//                "class myClass1\n{\n" +
//                "private int a = 0;\n" +
//                "int getValue()\n { return this.a; }\n" +
//                "}";
//
//        //直接将待生成.java文件以String形式输入writer，编译器会将这个流程产生的文件也进行生成
//        writer.write(classFileStr);
//
//        writer.flush();
//        writer.close();
//    }
    private String getVersion() {
        /**
         * 获取version，这里省略掉复杂的代码，直接返回固定值
         */
        return "v1.0.1";
    }
}
